use plugin_manager::PluginError;
use serde_json::Value;
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_void};

#[repr(C)]
pub struct CJson {
    _private: [u8; 0],
}

#[link(name = "cjson")]
unsafe extern "C" {
    fn cJSON_Parse(value: *const c_char) -> *mut CJson;
    fn cJSON_Print(item: *const CJson) -> *mut c_char;
    fn cJSON_Delete(item: *mut CJson);
    fn cJSON_free(ptr: *mut c_void);
}

/// Due to format differences between Rust's serde_json and cJson_Print when serializing json.
/// Itruttee_SDK use cJson_Print for serialization and subsequent signing.
/// Therefore, the verifier needs to use the same serialization method as cJson to generate identical digest values
pub fn cjson_print_from_value(value: &Value) -> Result<String, PluginError> {
    // 1. Convert to JSON string
    let json_str =
        serde_json::to_string(value).map_err(|e| PluginError::InternalError(format!("serde_json error: {}", e)))?;
    let c_json_str = CString::new(json_str).map_err(|e| PluginError::InternalError(format!("CString error: {}", e)))?;

    unsafe {
        // 2. Parse JSON
        let root = cJSON_Parse(c_json_str.as_ptr());
        if root.is_null() {
            return Err(PluginError::InternalError("cJSON_Parse failed".into()));
        }

        // 3. Print JSON
        let printed_ptr = cJSON_Print(root);
        if printed_ptr.is_null() {
            cJSON_Delete(root);
            return Err(PluginError::InternalError("cJSON_Print failed".into()));
        }

        // 4. Convert to Rust String
        let printed = CStr::from_ptr(printed_ptr).to_string_lossy().into_owned();

        // 5. Free memory
        cJSON_free(printed_ptr as *mut _);
        cJSON_Delete(root);

        Ok(printed)
    }
}
